/**
  ******************************************************************************
  * @file    Task.c
  * @author  Dajin Li
  * @version V0.0.1
  * @date    08-08-2015 
  * @brief   This file contains functions to initialize the OS.  
  *              
  *          
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; KION(SZ) R&D Center
  *
  * Licensed under KION, (the "License");
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/

#include "task.h"
#include "global.h"
#include "CAN.h"
#include "spi.h"
#include "var_tbl.h"
#include "lcd.h"
#include "Instrument.h"
#include "can_open.h"
#include "../user/bis.h"
#include "../swidft/swidft.h"
#include "deaddrop.h"
#include "deaddrop_bb.h"
#include "stm32_vector_table.h"


/* Functions ------------------------------------------------------------------*/
extern void CAN_task(void ); 
// thread object
extern void eeprom_task(void); 
extern void iwatchdog_task(void ); 


u8 stay_for_ever;
u16 stay_in_boot_time = 50;
 
const  s32 boot_bis_addr __attribute__((at(0x08000188)));

volatile u32 osTick;

    
/**
* @brief    Initializes PWM params to be used for lcd backlight and heater ctrl 
* @param    none
* @note     none
* @retval   none
*/
void Timer_Init(void)
{
    TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;
    TIM_OCInitTypeDef       TIM_OCInitStructure;

    //LCD PWM
    //TIM3CLK = 96 MHz, Prescaler = 0x0, TIM3 counter clock = 96 MHz
    //TIM3 ARR Register = 23999 => TIM3 Frequency = TIM3 counter clock/(ARR + 1)=4KHz = 0.25ms
    //TIM3 Channel3  output LCD backlight PWM control duty cycle = (TIM_Pulse/ TIM3_ARR)* 100

    TIM_DeInit(TIM3);
    
    TIM_BaseInitStructure.TIM_Period =23999;
    TIM_BaseInitStructure.TIM_Prescaler = 0;
    TIM_BaseInitStructure.TIM_ClockDivision = 0;
    TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_BaseInitStructure);

    //PWM1 Mode configuration: Channel4
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC4Init(TIM3, &TIM_OCInitStructure);
    
    TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
    TIM_ARRPreloadConfig(TIM3, ENABLE);
    
    TIM_UpdateDisableConfig(TIM3, DISABLE);
    TIM_Cmd(TIM3, ENABLE);  /* TIM3 enable counter */

    TIM_SetCompare4(TIM3, 12000); //update only if new value
    TIM_GenerateEvent(TIM3, TIM_EventSource_Update);
}

void EraseFlash(void)
{
    u8 i;
    u32 start_address = 0x8008000;
    FLASH_Status status;
    for(i = 0; i < 112; i++) // erase flash
    {
        if((i%10) == 0)
        {
            KWP_send_pending_msg();
        }
          /* Clear All pending flags */
        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);	
        IWDG_ReloadCounter();
        __set_PRIMASK(1);// disable interrupt
        FLASH_Unlock();
        status = FLASH_ErasePage(start_address);
        start_address += 2048;
        FLASH_Lock();
        __set_PRIMASK(0);// enable interrupt
        IWDG_ReloadCounter();

        if(status != FLASH_COMPLETE)
        {
            test_pattern(0x00);
            while(1)
            {
                IWDG_ReloadCounter();
                Display_H24_Str((u8 *)"ERASE ERR", 3, 36, 0);
            }
        }
    }
}
/**
* @brief    enable write protection.
* @param    none
* @note     none
* @retval   none 
*/
void enableWRP(u8 flag)
{
    IWDG_ReloadCounter();
    __set_PRIMASK(1);// disable interrupt   
    FLASH_Unlock();
    if(flag)
    {
        FLASH_EnableWriteProtection(FLASH_WRProt_AllPages);
    }
    else
    {
        FLASH_EnableWriteProtection(FLASH_WRProt_AllPages & 0xff);
    }


    FLASH_Lock();
    __set_PRIMASK(0);// enable interrupt
    IWDG_ReloadCounter();
}

/**
* @brief    enable write protection.
* @param    none
* @note     none
* @retval   none 
*/
void enableBOR(void)
{
   
}


/**
* @brief    enable read protection.
* @param    none
* @note     none
* @retval   none 
*/
void enableRDP(void)
{
    IWDG_ReloadCounter();
    __set_PRIMASK(1);// disable interrupt   
    FLASH_Unlock();
    FLASH_ReadOutProtection(ENABLE);
    FLASH_Lock();
    __set_PRIMASK(0);// enable interrupt
    IWDG_ReloadCounter();
}




/**
* @brief    It creates and starts all other tasks. 
* @param    none
* @note     none
* @retval   none
*/
void create_tasks(void) 
{
    struct bis *boot_bis = (struct bis *)(*(u32 *)BootBISAddress);
    u32 crc_32;
    
    EE_SPI_Init();
    CAN_Config();
    Timer_Init(); 
    IWDG_ReloadCounter();

    enableBOR();

    stay_for_ever = 0;
    stay_in_boot_time = 50;

    CRC_ResetDR();


    if(boot_bis == 0)
    {
        while(1);
    }
    else
    {
    
        crc_32 = CRC_CalcBlockCRC((u32 *)boot_bis, BIS_LEN);
        if(crc_32 != boot_bis->bis_checksum)
        {
            while(1);
        }
    }
    
    CRC_ResetDR();

    if(boot_bis->checksum_start == 0 ||  boot_bis->checksum_len == 0 || boot_bis == 0)
    {
        while(1);
    }
    else
    {
        crc_32 = CRC_CalcBlockCRC((u32 *)(boot_bis->checksum_start), boot_bis->checksum_len);
        if(crc_32 != boot_bis->checksum_value)
        {
           while(1);
        }
    }

    swidft_software_id_from_time(boot_bis->build_time, (CH*)software_id); // get boot software id

    load_parameters_from_ee();
    if( deadrop_is_stay_in_bb_flag()) // updated flash from application
    {
        stay_for_ever = 1;
        deadrop_clear_stay_in_bb_flag();
        LCD_init();             //initialize monochrome 240x320 display
        test_pattern(0x00);
        if((FLASH_GetWriteProtectionOptionByte() & (0x0000ffff)) > 0)
        {
            enableWRP(0);   
        }
        stay_for_ever = 1;
        CAN_task();
    }
    else 
    {
        stay_for_ever = 0;
        CAN_task();
    
        deadrop_set_start_application_flag();
        if((FLASH_GetWriteProtectionOptionByte() &  FLASH_WRProt_AllPages)!= FLASH_WRProt_AllPages)
        {
            enableWRP(1);   
        } 
    
        if(FLASH_GetReadOutProtectionStatus() != SET)
        {
            enableRDP();   
        }
        NVIC_SystemReset(); 

    }
}

void JumpToApp(void)
{
     struct stm32_vector_table const * const vtab = (void*)ApplicationSwAddress;
     if(*(u32*)(DEADDROP_RAM_ADDR + 4) == VALID_FLAG_VALUE)
     {
        //deadrop_clear_start_application_flag();
        *(u32*)(DEADDROP_RAM_ADDR + 4) = ~VALID_FLAG_VALUE;
        __set_MSP(*(__IO u32*) ApplicationSwAddress);  // Initialize user application's Stack Pointer 
        SCB->VTOR = ApplicationSwAddress;
        vtab->reset();
    }
 }



